﻿/****************************************************
	文件：EditorUtil.cs
	作者：HuskyT
	邮箱: 1005240602@qq.com
	日期：2021/07/03 12:52:32   	
	功能：编辑器常用工具API
*****************************************************/

using System;
using System.Collections.Generic;
using System.Text;
using HTFramework.Extension;
using UnityEditor;
using UnityEngine;

namespace HTFramework.Utility.Editor
{
    public class EditorUtil
    {
        //------------------------------  Unity编辑器相关  ------------------------------//

        #region Unity编辑器相关

        /// <summary>
        /// 复用菜单方法
        /// </summary>
        /// <param name="menuItemPath">菜单方法路径</param>
        public static void ReuseMenuItem(string menuItemPath)
        {
            EditorApplication.ExecuteMenuItem(menuItemPath);
        }

        /// <summary>
        /// 打开文件夹
        /// </summary>
        /// <param name="folderPath">文件夹路径</param>
        public static void OpenFolder(string folderPath)
        {
            Application.OpenURL("file:///" + folderPath);
            //EditorUtility.RevealInFinder(Application.persistentDataPath);
        }

        /// <summary>
        /// 将指定资源导出成UnityPackage
        /// </summary>
        /// <param name="assetPathName">待导出资源路径</param>
        /// <param name="fileName">导出文件的文件名</param>
        public static void ExportUnityPackage(string assetPathName, string fileName)
        {
            EditorUtility.DisplayProgressBar("导出当前项目", $"{Application.productName}正导出为UnityPackage",
                0.1f);
            //递归导出指定文件夹下所有文件
            AssetDatabase.ExportPackage(assetPathName, fileName, ExportPackageOptions.Recurse);
            EditorUtility.DisplayProgressBar("导出当前项目", $"{Application.productName}正导出为UnityPackage",
                1f);
            EditorUtility.ClearProgressBar();
        }
 
        /// <summary>
        /// 生成UnityPackage名
        /// 默认：项目名_日期.unitypackage
        /// </summary>
        /// <returns></returns>
        public static string GenerateUnityPackageName(string packageName = null)
        {
            if (packageName == null)
            {
                string projectName = Application.productName;
                return projectName + "_" + DateTime.Now.ToString("yyyyMMdd_HH") + ".unitypackage";
            }
            else
            {
                return packageName + "_" + DateTime.Now.ToString("yyyyMMdd_HH") + ".unitypackage";
            }
        }

        /// <summary>
        /// 打开/运行指定文件
        /// </summary>
        /// <param name="fileFullPath">文件的完整路径，包括后缀</param>
        public static void OpenFile(string fileFullPath)
        {
            System.Diagnostics.Process.Start(fileFullPath);
        }

        /// <summary>
        /// 打开当前项目
        /// </summary>
        public static void OpenCurrentProject()
        {
            EditorApplication.OpenProject(Application.dataPath.Replace("Assets", string.Empty));
        }

        #endregion


        //------------------------------  提供脚本编译完成后的回调注册  ------------------------------//

        #region 提供脚本编译完成后的回调注册

        /// <summary>
        /// 存储回调字符串
        /// </summary>
        private static string mOnCompiledCallBackStr;

        /// <summary>
        /// 存储用的Key
        /// </summary>
        public const string SAVE_KEY_COMPILED_CALL_BACK = "SAVE_KEY_COMPILED_CALL_BACK";

        /// <summary>
        /// 注册脚本编译完成后的回调
        /// </summary>
        /// <param name="funcName">回调方法名</param>
        /// <param name="nameSpace">回调所在的命名空间</param>
        /// <param name="className">回调所在的类</param>
        public static void SubscribeCompileFinishedCallBack(string funcName, string nameSpace, string className)
        {
            string fullFuncStr = $"{nameSpace}.{className}.{funcName};";
            mOnCompiledCallBackStr = mOnCompiledCallBackStr + ";" + fullFuncStr;
            PlayerPrefs.SetString(SAVE_KEY_COMPILED_CALL_BACK, mOnCompiledCallBackStr);
        }

        /// <summary>
        /// 注销脚本编译完成后的回调
        /// </summary>
        /// <param name="funcName">回调方法名</param>
        /// <param name="nameSpace">回调所在的命名空间</param>
        /// <param name="className">回调所在的类</param>
        public static void UnsubscribeCompileFinishedCallBack(string funcName, string nameSpace, string className)
        {
            string fullFuncStr = $"{nameSpace}.{className}.{funcName};";
            mOnCompiledCallBackStr = mOnCompiledCallBackStr.Replace(fullFuncStr, string.Empty);
            PlayerPrefs.SetString(SAVE_KEY_COMPILED_CALL_BACK, mOnCompiledCallBackStr);
        }

        /// <summary>
        /// 注销所有脚本编译完成后的回调
        /// </summary>
        public static void UnsubscribeAllCompileFinishedCallBack()
        {
            mOnCompiledCallBackStr = string.Empty;
            PlayerPrefs.SetString(SAVE_KEY_COMPILED_CALL_BACK, mOnCompiledCallBackStr);
        }

        /// <summary>
        /// 脚本编译完成后调用该方法（尚不完善，目前只支持转表工具使用）
        /// </summary>
        [UnityEditor.Callbacks.DidReloadScripts]
        private static void OnCompileFinished()
        {
            //解析方法：
            string allFuncStr = PlayerPrefs.GetString(SAVE_KEY_COMPILED_CALL_BACK, string.Empty);
            if (string.IsNullOrEmpty(allFuncStr)) return;
            string[] funcStrArray = allFuncStr.Split(';');
            if (funcStrArray.Length <= 0) return;
            foreach (string funcStr in funcStrArray)
            {
                if (string.IsNullOrEmpty(funcStr)) continue;
                string[] funcInfo = funcStr.Split('.'); //funcStr：HTFW.Scheme.SchemeToolsEditor.ConvertAfterCompile
                if (funcInfo.Length <= 0) continue;
                string nameSpace = funcInfo[0] + "." + funcInfo[1]; //TODO 此处为特殊处理，尚待改进
                string className = funcInfo[2];
                string funcName = funcInfo[3];
                //反射调用
                object obj = RuntimeUtil.CreateClassObj($"{nameSpace}.{className}");
                RuntimeUtil.InvokeMethod(obj, funcName);
                Debug.LogFormat("编译完成后，反射调用：{0}", funcName);
            }

            UnsubscribeAllCompileFinishedCallBack();
        }

        /// <summary>
        /// 生成一个无用的CSharp脚本，用于启用编译后的回调
        /// </summary>
        public static void GenerateNoUseScript()
        {
            string folderPath = "Assets/Misc/CanDelete/";
            string scriptName = "NoUse.cs";
            RuntimeUtil.CheckOrCreateFolder(folderPath);
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(
                $"//日期：{string.Concat(DateTime.Now.Year, "/", DateTime.Now.Month, "/", DateTime.Now.Day, " ", DateTime.Now.Hour, ":", DateTime.Now.Minute, ":", DateTime.Now.Second)}");
            //命名空间
            sb.AppendLine($"namespace {HConst.CommonConst.NAME_SPACE}");
            sb.AppendLine("{");
            //类名
            sb.AppendLine("\t[Serializable]");
            sb.AppendLine($"\tpublic class NoUse");
            sb.AppendLine("\t{");
            sb.AppendLine("\t}");
            sb.AppendLine("}");
            RuntimeUtil.WriteStringToFile(sb.ToString(), folderPath + scriptName, Encoding.UTF8);
        }

        #endregion


        //------------------------------  代码生成  ------------------------------//

        #region 代码生成

        /// <summary>
        /// 编辑脚本头信息
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="className"></param>
        /// <param name="userName"></param>
        public static void EditHeadInfo(ref StringBuilder sb, string className, string userName, string mail)
        {
            sb.AppendLine("/****************************************************");
            sb.AppendLine($"\t文件：{className}.cs");
            sb.AppendLine($"\t作者：{userName}");
            sb.AppendLine($"\t邮箱：{mail}");
            sb.AppendLine(
                $"\t日期：{DateTime.Now.Year}/{DateTime.Now.Month}/{DateTime.Now.Day} {DateTime.Now.Hour}:{DateTime.Now.Minute}:{DateTime.Now.Second}");
            sb.AppendLine("\t功能：");
            sb.AppendLine("*****************************************************/");
            sb.AppendLine();
        }

        /// <summary>
        /// 编辑Using
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="usingName"></param>
        public static void EditUsing(ref StringBuilder sb, string usingName)
        {
            sb.AppendLine($"using {usingName};");
        }

        /// <summary>
        /// 编辑命名空间
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="nameSpace"></param>
        public static void EditNameSpace(ref StringBuilder sb, string nameSpace)
        {
            sb.AppendLine($"namespace {nameSpace}");
        }

        /// <summary>
        /// 编辑类名
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="className"></param>
        /// <param name="inherit"></param>
        public static void EditClassName(ref StringBuilder sb, string className, string inherit)
        {
            sb.AppendLine(inherit == string.Empty
                ? $"\tpublic class {className}"
                : $"\tpublic class {className} : {inherit}");
        }

        /// <summary>
        /// 编辑成员变量
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="fieldName"></param>
        /// <param name="isPublic"></param>
        /// <param name="isStatic"></param>
        /// <param name="fieldType"></param>
        public static void EditField(ref StringBuilder sb, string fieldName, bool isPublic, bool isStatic,
            string fieldType, string initValue)
        {
            string accessSpecifier = isPublic ? "public" : "private"; //访问修饰符
            string specifier = isStatic ? " static" : ""; //修饰符
            sb.AppendLine(string.IsNullOrEmpty(initValue)
                ? $"\t\t{accessSpecifier}{specifier} {fieldType} {fieldName};"
                : $"\t\t{accessSpecifier}{specifier} {fieldType} {fieldName} = {initValue};");
        }

        /// <summary>
        /// 编辑方法
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="isPublic"></param>
        /// <param name="isStatic"></param>
        /// <param name="retStr"></param>
        /// <param name="funcName"></param>
        /// <param name="paramLst"></param>
        /// <param name="innerInfo"></param>
        public static void EditFunction(ref StringBuilder sb, bool isPublic, bool isStatic, string retStr,
            string funcName, List<string> paramLst, string innerInfo, string funcBody = "")
        {
            string accessSpecifier = isPublic ? "public" : "private"; //访问修饰符
            string specifier = isStatic ? " static" : ""; //修饰符
            retStr = retStr == string.Empty ? "void" : retStr; //返回值
            string paramStr = ""; //参数列表
            if (paramLst.IsNullOrEmpty() == false)
            {
                for (int i = 0; i < paramLst.Count; i++)
                {
                    string space = i == paramLst.Count - 1 ? "" : " ,";
                    paramStr += $"{paramLst[i]}{space}";
                }
            }

            sb.AppendLine($"\t\t{accessSpecifier}{specifier} {retStr} {funcName}({paramStr})");
            sb.AppendLine("\t\t{");
            if (!string.IsNullOrEmpty(innerInfo))
                sb.AppendLine($"\t\t\t//{innerInfo}");
            if (!string.IsNullOrEmpty(funcBody))
                sb.Append($"{funcBody}");
            sb.AppendLine("\t\t}");
        }

        public static void EditFunction(ref StringBuilder sb, string publicStr, bool isStatic, bool isOverride,
            string retStr, string funcName, List<string> paramLst, string addStr, string innerInfo)
        {
            string accessSpecifier = publicStr; //访问修饰符
            string specifier = isStatic ? " static" : ""; //static 修饰符
            string overrideStr = isOverride ? " override" : ""; //override 修饰符
            retStr = retStr == string.Empty ? " void" : retStr; //返回值
            retStr = retStr == "null" ? "" : retStr; //返回值
            string paramStr = ""; //参数列表
            if (paramLst.IsNullOrEmpty() == false)
            {
                for (int i = 0; i < paramLst.Count; i++)
                {
                    string space = i == paramLst.Count - 1 ? "" : " ";
                    paramStr += $"{paramLst[i]},{space}";
                }
            }

            paramStr = paramStr == "" ? "" : paramStr.TrimEnd(',');

            addStr = addStr == string.Empty ? "" : " " + addStr;
            sb.AppendLine($"\t\t{accessSpecifier}{specifier}{overrideStr}{retStr} {funcName}({paramStr}){addStr}");
            sb.AppendLine("\t\t{");
            sb.AppendLine(innerInfo == string.Empty ? "" : $"\t\t\t//{innerInfo}");
            sb.AppendLine("\t\t}");
        }

        /// <summary>
        /// 获取类名
        /// </summary>
        /// <param name="content">脚本内容</param>
        /// <returns></returns>
        public static string GetClassName(string content)
        {
            string[] strArray = content.Split(' ');
            for (int i = 0; i < strArray.Length; i++)
            {
                if (strArray[i] == "class")
                {
                    return strArray[i + 1];
                }
            }

            return null;
        }

        #endregion
    }
}